package NetNode

import (
	"PBMessage"
	"Player"

	"github.com/golang/protobuf/proto"

	"git.oschina.net/yangdao/SGNet2"
	"git.oschina.net/yangdao/SGNet2/BuiltinProtocol"
	"git.oschina.net/yangdao/extlib/data_type"
	"git.oschina.net/yangdao/extlib/log"
	"git.oschina.net/yangdao/goerl"
)

//NetNode 网络节点 管理所有连接
type NetNode struct {
	workNode  *goerl.Node
	sessions  map[int64]*SGNet2.Session
	lobbyNode *goerl.Node
	gameNode  *goerl.Node
}

//New 创建网络节点
func New() *NetNode {
	retNode := &NetNode{
		sessions:  make(map[int64]*SGNet2.Session),
		lobbyNode: goerl.GetNode("LobbyNode"),
	}
	retNode.workNode = goerl.NewNode(retNode.receiveFunc)
	<-goerl.Register("NetNode", retNode.workNode)
	return retNode
}

//Start 启动网络节点 会阻塞住代码最好在最后一个启动
func (netNode *NetNode) Start() {
	netNode.workNode.Start()

	protocol := BuiltinProtocol.NewPBSizeAndId()
	netServer := SGNet2.NewNetServer(data_type.HashMap("port", "6542"), log.DefaultLogger, protocol)
	netServer.SGNetMessage = func(sess *SGNet2.Session, msgType int) {
		goerl.Send(netNode.workNode, []interface{}{":SessionStateMail", sess, msgType})
	}
	netServer.AddPacketEvent(func(sess *SGNet2.Session, id uint16, data []byte) {
		msg := PBMessage.GetPBMessageByID(int32(id))
		proto.Unmarshal(data, msg)
		goerl.Send(netNode.workNode, []interface{}{":ClientMail", id, msg, sess})
	})
	netServer.Run()
}

func (netNode *NetNode) receiveFunc(msg interface{}) {
	switch msg.(type) {
	case []interface{}:
		tuple := msg.([]interface{})
		msghead := tuple[0].(string)
		switch msghead {
		//客户端发送的消息
		case ":ClientMail":
			sess := tuple[3].(*SGNet2.Session)
			netPlayer := sess.UserData.(*netPlayerState)
			if netPlayer.state == Player.PlayerStateGame {
				goerl.Send(netPlayer.gameNode, tuple)
			} else if netPlayer.state == Player.PlayerStateLobby || netPlayer.state == Player.PlayerStateUnLogin {
				goerl.SendByName("LobbyNode", tuple)
			}
		//会话的连接与断开
		case ":SessionStateMail":
			sess := tuple[1].(*SGNet2.Session)
			msgType := tuple[2].(int)
			switch msgType {
			case SGNet2.SGNetMsg_SessionNew:
				netNode.sessions[sess.ID] = sess
				sess.UserData = &netPlayerState{state: Player.PlayerStateUnLogin}
			case SGNet2.SGNetMsg_SessionLost:
				delete(netNode.sessions, sess.ID)
				node := sess.UserData.(*netPlayerState)
				if node.state == Player.PlayerStateUnLogin {
					return
				}
				if node.state == Player.PlayerStateGame {
					goerl.Send(node.gameNode, tuple)
				}
				goerl.SendByName("LobbyNode", tuple)
			}
		case ":CmdMail":
			cmd := tuple[1].(string)
			switch cmd {
			case ":player-state-change":
				sessID := tuple[2].(int64)
				netPlayer := netNode.sessions[sessID].UserData.(*netPlayerState)
				netPlayer.state = tuple[3].(int)
				if netPlayer.state == Player.PlayerStateGame {
					netPlayer.gameNode = tuple[4].(*goerl.Node)
				}
			}
		case ":ToClientMail":
			//fmt.Println(tuple)
			netNode.sessions[tuple[1].(int64)].Send(tuple[2].(int), tuple[3].(proto.Message))
		}
	}
}

type netPlayerState struct {
	state    int
	gameNode *goerl.Node
}

/*
          LobbyNode GameNode

	  GateNode
	   Session

	   Client
*/
